#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#include <dirent.h>
#include <sys/time.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/socket.h>

#include "data_type.h"
#include "cube.h"
#include "cube_define.h"
#include "cube_record.h"

#include "sm2.h"

#include "user_define.h"
#include "record_define.h"
#include "crypt_define.h"

#include "crypt_sign.h"

struct timeval time_val={0,50*1000};

int crypt_sign_init(void * sub_proc,void * para)
{
	int ret;
	// add youself's plugin init func here
	return 0;
}

int crypt_sign_start(void * sub_proc,void * para)
{
	int ret;
	void * recv_msg;
	int i;
	int type;
	int subtype;

	while(1)
	{
		usleep(time_val.tv_usec);
		ret=ex_module_recvmsg(sub_proc,&recv_msg);
		if(ret<0)
			continue;
		if(recv_msg==NULL)
			continue;
	
		if(message_get_flag(recv_msg) &MSG_FLAG_SIGN)
			proc_verify_message(sub_proc,recv_msg);
		else
			proc_sign_message(sub_proc,recv_msg);
	}
	return 0;

}

int proc_sign_message(void * sub_proc,void * recv_msg)
{
        int i;
        int ret;

        BYTE Buf[DIGEST_SIZE*16];
        unsigned long sign_len=512;

        MSG_EXPAND * msg_expand;
        RECORD(CRYPT_DEFINE,LOCAL_KEYSET) * local_keyset;
        RECORD(CRYPT_DEFINE,DATA_SIGN) * data_sign;

        BYTE * blob;
        int blob_size;
        char * UserID="ALICE123@YAHOO.COM";

        unsigned long lenUID;

	    ret = message_remove_expand(recv_msg,TYPE_PAIR(CRYPT_DEFINE,LOCAL_KEYSET),&msg_expand);
	    if(ret<0)
		    return ret;
	    if(msg_expand == NULL)	// sign data
        {
			print_cubeerr("crypt_manage: can't find keyset for sign!");
			return -EINVAL;
        }
        local_keyset=msg_expand->expand;

        // get record's bin blob
        blob_size=message_get_blob(recv_msg,&blob);
        if(blob_size<=0)
                return -EINVAL;
        
        lenUID=Strlen(UserID);
        
        ret = GM_SM2Sign(Buf,&sign_len,blob,(unsigned long)blob_size,UserID,lenUID,
            local_keyset->privkey,(unsigned long)local_keyset->privkey_len);
        if(ret<0)
        {
            print_cubeerr("crypt_sign: sign data failed! error %d!",ret);
            return -EINVAL;
        }

        data_sign=Talloc0(sizeof(*data_sign));
        if(data_sign==NULL)
        {
            print_cubeerr("crypt_sign: malloc data failed!");
            return -EINVAL;
        }
        
		Memcpy(data_sign->node_uuid,local_keyset->node_uuid,DIGEST_SIZE);
		data_sign->user_name=dup_str(local_keyset->user_name,DIGEST_SIZE);
		data_sign->signdata_size=sign_len;
        data_sign->signdata=Talloc0(sign_len);
        Memcpy(data_sign->signdata,Buf,sign_len);
	    
        message_add_expand_data(recv_msg,TYPE_PAIR(CRYPT_DEFINE,DATA_SIGN),data_sign);

	    int flag=message_get_flag(recv_msg);
        message_set_flag(recv_msg,flag | MSG_FLAG_SIGN);

        ex_module_sendmsg(sub_proc,recv_msg);
        return ret;
}

int proc_verify_message(void * sub_proc,void * recv_msg)
{
        int i;
        int ret;

        BYTE * blob;
        int blob_size;

        MSG_EXPAND * msg_expand;
        RECORD(CRYPT_DEFINE,PUBLIC_KEY) * public_key;
        RECORD(CRYPT_DEFINE,DATA_SIGN) * data_sign;

        char * UserID="ALICE123@YAHOO.COM";

        unsigned long lenUID;

	    ret = message_remove_expand(recv_msg,TYPE_PAIR(CRYPT_DEFINE,PUBLIC_KEY),&msg_expand);
	    if(ret<0)
		    return ret;
	    if(msg_expand == NULL)	// sign data
        {
			print_cubeerr("crypt_sign: can't find public key for verify!");
			return -EINVAL;
        }
        public_key=msg_expand->expand;

	    ret = message_remove_expand(recv_msg,TYPE_PAIR(CRYPT_DEFINE,DATA_SIGN),&msg_expand);
	    if(ret<0)
		    return ret;
	    if(msg_expand == NULL)	// sign data
        {
			print_cubeerr("crypt_sign: can't find data sign for verify!");
			return -EINVAL;
        }
        data_sign =msg_expand->expand;

        // get record's bin blob
        blob_size=message_get_blob(recv_msg,&blob);
        if(blob_size<=0)
                return -EINVAL;
        
        lenUID=Strlen(UserID);
        
        ret = GM_SM2VerifySig(data_sign->signdata,(unsigned long)data_sign->signdata_size,blob,
                (unsigned long)blob_size,UserID,lenUID,
                public_key->pubkey,public_key->pubkey_len);
        if(ret<0)
        {
            print_cubeerr("crypt_sign: verify data failed! error %d!",ret);
            return -EINVAL;
        }

	    int flag=message_get_flag(recv_msg);
        message_set_flag(recv_msg,flag&(~MSG_FLAG_SIGN));

        ex_module_sendmsg(sub_proc,recv_msg);
        return ret;
}
